
/**
 * 两个数组求交集，共同的部分
 * 
 * e.g.1 
 * cross([1, 2], [1, 3])       // [1]
 */
export function cross(arr1: any[], arr2: any[], field?: string) {
    if (!field) return arr1.filter(item => arr2.includes(item))

    return arr1.filter(item => item).filter(item => {
        if (typeof item !== 'object') {
            return arr2.includes(item)
        } else {
            return !!arr2.find(item2 => item[field] === item2[field])
        }
    })
}

/**
 * 求数组交集，参数可以是个二维数组
 * 
 * const result = crossPlus(
 *      [
 *          [{'name': 'a1'}],
 *          [{'name': 'a1'}, {'name': 'a2'}],
 *          [{'name': 'a1'}, {'name': 'a3'}],
 *      ],
 *      'name'
 * )
 * // [{'name': 'a1'}]
 * 
 * const result = darr.crossPlus([
 *      [1,2,3],
 *      [2,3,4],
 *      [2,5,8],
 * ])
 * // [2]
 */
export function crossPlus(twoDimensionalArr: any[][] = [], field?: string) {
    if (twoDimensionalArr.length === 0) return []
    const result = twoDimensionalArr.reduce((prev: any[], curr: any[]) => {
        return cross(prev, curr, field)
    }, twoDimensionalArr[0])
    return result
}

/**
 * 两个数组求差集，不同的部分
 * 
 * e.g.1   
 * diff([1, 2], [1, 3])        // [2, 3]
 */
export function diff(arr1: any[], arr2: any[]) {
    const diff: any[] = []
    arr1 = [...arr1]
    arr2 = [...arr2]

    arr1.forEach(function (val1, i) {
        if (arr2.indexOf(val1) < 0) {
            diff.push(val1)
        } else {
            arr2.splice(arr2.indexOf(val1), 1)
        }
    })

    return diff.concat(arr2)
}

/**
 * 数组去重
 * 
 * e.g.1 一般数据结构数组去重  
 * const arr1 = [1, 2, 1, 3, 1]   
 * darr.unique(arr1)   
 * // [1, 2, 3]
 * 
 * e.g.2 对象数组去重，第二个参数指定对象的字段值  
 * const arr2 = [  
 *      { id: '1', name: 'dkvirus' },  
 *      { id: '2', name: 'dreamlin' },   
 *      { id: '3', name: 'dkvirus' },  
 * ]  
 * // 根据对象字面量中 name 字段值重复的去重，第二个参数可以写多个字段值  
 * unique(arr2, ['name'])  
 * // [  
 * //		{ id: '1', name: 'dkvirus' },  
 * //  	    { id: '2', name: 'dreamlin' },  
 * // ]  
 */
export function unique(arr: any[], fields?: any[]): any[] {
    if (!fields || fields?.length === 0) {
        return Array.from(new Set(arr))
    }

    // 对象数组去重
    const result: any[] = []
    // 利用对象字面量键值唯一性处理对象数组去重
    const obj: Record<string, any> = {}
    arr.forEach(item => {
        if (Object.prototype.toString.call(item) === '[object Object]') {
            const key = fields.map(field => String(item[field])).join('-')
            if (!obj[key]) {
                result.push(item)
                obj[key] = item
            }
        } else {
            result.push(item)
        }
    })
    return Array.from(new Set(result))
}

/**
 * 递归改变数组内数据结构
 */
export function recursion(data: any[], fieldsOrcb: ((item: any) => void) | Record<string, any>, mode: 'append' | 'new' = 'append'): any[] {
    const iterator = function (arr: any[], cb: Function) {
        for (let i = 0; i < arr.length; i++) {
            cb.call(arr[i], arr[i])
        }
    }

    const changeItem = function (item: any) {
        if (typeof fieldsOrcb === 'function') {
            fieldsOrcb(item)
        } else if (Object.prototype.toString.call(fieldsOrcb) === '[object Object]') {
            Object.keys(fieldsOrcb).forEach(key => {
                item[key] = item[fieldsOrcb[key]]
            })

            if (mode === 'new') { // 删除原有字段
                const arr1 = Object.keys(item)
                const arr2 = Object.keys(fieldsOrcb)
                const arr3 = arr1.filter(a1 => {
                    return !arr2.includes(a1) && a1 !== 'children'
                })
                arr3.forEach(a3 => delete item[a3])
            }
        }

        if (item.children) {
            iterator(item.children, changeItem)
        }
    }

    iterator(data, changeItem)
    return [...data]
}

/**
 * 数组生成驼峰字符串
 * @param arr 
 * @param mode 'lower' | 'upper'，默认为 lower，生成小驼峰
 */
export function camelCase(arr: string[], mode: 'lower' | 'upper' = 'lower'): string {
    if (arr.length === 0) return ''
    arr = arr.map((item: string, index: number) => {
        if (index === 0 && mode === 'lower') {
            return item.charAt(0).toLowerCase() + item.slice(1)
        }
        return item.charAt(0).toUpperCase() + item.slice(1)
    })
    return arr.join('')
}

/**
 * 合并数组对象
 * @param arr1 any[]
 * @param arr2 any[]
 * @param fields string[]
 */
export function mergeObjArr(arr1: any[] = [], arr2: any[] = [], fieldsArrOrObj: string[] | Record<string, any>): any[] {
    const getKey = (item: Record<string, any>, arrType: 'arr1' | 'arr2') => {
        let key = ''
        if (Array.isArray(fieldsArrOrObj)) {
            fieldsArrOrObj.forEach(item2 => {
                key += item[item2]
            })
        } else if (Object.prototype.toString.call(fieldsArrOrObj) === '[object Object]') {
            if (arrType === 'arr1') {
                Object.keys(fieldsArrOrObj).forEach(item2 => {
                    key += item[item2]
                })
            } else {
                Object.values(fieldsArrOrObj).forEach((item2: any) => {
                    key += item[item2]
                })
            }
        }
        return key
    }

    const obj: Record<string, any> = {}
    arr2.forEach((item: any) => {
        const key = getKey(item, 'arr2')
        obj[key] = item
    })

    return arr1.map(item => {
        const key = getKey(item, 'arr1')
        if (key && obj[key]) {
            return { ...item, ...obj[key] }
        } else {
            return { ...item }
        }
    })
}

/**
 * 获取数组最后一项
 */
export function last(arr: any[]): any {
    if (arr.length === 0) {
        return undefined
    } else {
        return arr[arr.length - 1]
    }
}

export default {
    cross,
    crossPlus,
    diff,
    unique,
    recursion,
    camelCase,
    mergeObjArr,
    last,
}